﻿//using Leadshine;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
namespace MotionIoLib
{
    public class Motion_LTDMC3400 : MotionCardBase
    {
        private ushort _ConnecNo = 0;
        public Motion_LTDMC3400(ulong indexCard, string strName, int nMinAxisNo, int nMaxAxisNo)
    : base(indexCard, strName, nMinAxisNo, nMaxAxisNo)
        {
        }

        public override bool AbsMove(int nAxisNo, double nPos, double nSpeed)
        {
            //if(nAxisNo == 0)
            //{
            //    int ret = 0;
            //    LTDMC.smc_get_stop_reason(_ConnecNo, (ushort)nAxisNo, ref ret);
            //    MessageBox.Show(ret.ToString());
            //}
            double pos = GetMotorType(nAxisNo) == MotorType.STEP ? GetAxisCmdPos(nAxisNo) : GetAxisActPos(nAxisNo);
            pos = nPos - pos;
            RelativeMove(nAxisNo, pos, nSpeed);
            return true;
        }

        public override bool AddAxisToGroup(int[] nAxisarr, ref object groupId)
        {
            return true;
        }
        List<object> list = new List<object>();
        public override bool SetBufMoveParam(object objGroup, ushort[] axisList, double velhigh, double vellow, double acc, double dec, ref string strError)
        {
            if (!list.Contains(objGroup))
                list.Add(objGroup);
            ushort CrdNo = (ushort)list.IndexOf(objGroup);
            if (velhigh == 0 || velhigh == 1 || velhigh == 2)
                velhigh += 0.01;
            if (vellow == 0 || vellow == 1 || vellow == 2)
                vellow += 0.01;
            List<double> list_VelHigh = new List<double>();
            List<double> list_VelLow = new List<double>();
            for (int i = 0; i < axisList.Length; i++)
            {
                double d_velHigh = velhigh;
                double d_velLow = vellow;
                TranMMToPluse(axisList[i], ref d_velHigh, ref acc, ref dec);
                TranMMToPluse(axisList[i], ref d_velLow, ref acc, ref dec);
                list_VelHigh.Add(d_velHigh);
                list_VelLow.Add(d_velLow);
            }
            velhigh = list_VelHigh.Min();
            vellow = list_VelLow.Min();
            //矩形插补运动非前瞻模式(dmc_conti_set_lookahead_mode)：前瞻模式矩形拐角会平滑处理变成圆弧，无法到达矩形端点；非前瞻模式则精确到达矩形端点
            int ret = LTDMC.dmc_conti_set_lookahead_mode(_ConnecNo, CrdNo, 1, 200, 500, 90000000);
            strError += $"lookahead_mode={ret}";
            ret = LTDMC.dmc_conti_open_list(_ConnecNo, CrdNo, (ushort)axisList.Length, axisList);
            strError += $"open_list={ret}";
            ret = LTDMC.dmc_set_vector_profile_unit(_ConnecNo, CrdNo, vellow, velhigh, acc, dec, vellow);
            strError += $"profile_unit={ret}";
            return ret == 0; ;
        }

        public override bool AddBufDelay(object objGroup, int nTime, ref string strError)
        {
            if (nTime <= 0)
                return true;
            ushort CrdNo = (ushort)list.IndexOf(objGroup);
            double time = nTime / 1000.0;
            int ret = LTDMC.dmc_conti_delay(_ConnecNo, CrdNo, time, 0);
            strError = ret.ToString();
            return true;
        }

        public override bool AddBufIo(object objGroup, string strIoName, bool bVal, ref string strError)
        {
            ushort CrdNo = (ushort)list.IndexOf(objGroup);

            var nIoIndex = IOMgr.GetInstace().GetOutputDic()[strIoName]._IoIndex;
            int ret = LTDMC.dmc_conti_write_outbit(_ConnecNo, CrdNo, (ushort)nIoIndex, (ushort)(bVal ? 0 : 1), 0);
            strError = ret.ToString();
            return true;
        }

        public override bool AddBufMove(object objGroup, BufMotionType type, int mode, ushort[] axisList, double velHigh, double velLow, double[] Point1, double[] Point2, int Circle, ref string strError)
        {
            ushort CrdNo = (ushort)list.IndexOf(objGroup);

            ushort dirction = 0;
            if (type == BufMotionType.buf_Arc2dAbsCW)
            {
                dirction = 1;
            }
            else if (type == BufMotionType.buf_Arc2dAbsCCW)
            {
                dirction = 0;
            }
            var ret = 0;
            if (type == BufMotionType.buf_Arc2dAbsCCW || type == BufMotionType.buf_Arc2dAbsCW)
            {
                ret = LTDMC.dmc_conti_arc_move_center_unit(_ConnecNo, CrdNo, (ushort)axisList.Length, axisList, Point2, Point1, dirction, Circle - 1, 1, 0);
                return ret == 0;
            }
            else if (type == BufMotionType.buf_Line2dAbs || type == BufMotionType.buf_Line3dAbs)
            {
                ret = LTDMC.dmc_conti_line_unit(_ConnecNo, CrdNo, (ushort)axisList.Length, axisList, Point2, 1, 0);
            }
            strError = ret.ToString();
            return ret == 0;
        }
        public override bool ClearBufMove(object objGroup)
        {
            ushort CrdNo = (ushort)list.IndexOf(objGroup);

            LTDMC.dmc_conti_close_list(_ConnecNo, CrdNo);
            return true;
        }

        public override bool Close()
        {
            short e = LTDMC.dmc_board_close();
            return true;
        }

        public override int GetAxisActPos(int nAxisNo)
        {
            double pos = 0;
            if(GetMotorType(nAxisNo)==MotorType.STEP)
                LTDMC.dmc_get_position_unit(_ConnecNo, (ushort)nAxisNo, ref pos);
            else
                LTDMC.dmc_get_encoder_unit(_ConnecNo, (ushort)nAxisNo, ref pos);
            return (int)pos;
        }

        public override int GetAxisCmdPos(int nAxisNo)
        {
            double pos = 0;
            LTDMC.dmc_get_position_unit(_ConnecNo, (ushort)nAxisNo, ref pos);
            return (int)pos;
        }

        public override int GetAxisPos(int nAxisNo)
        {
            double pos = 0;
            LTDMC.dmc_get_position_unit(_ConnecNo, (ushort)nAxisNo, ref pos);
            return (int)pos;
        }

        public override long GetMotionIoState(int nAxisNo)
        {
            long lStandardIo = 0;
            uint status = LTDMC.dmc_axis_io_status(_ConnecNo, (ushort)nAxisNo);



           bool ALM  = ((int)status & 1) == 1;
           bool ELP  = ((int)status & 2) == 2;
           bool ELN  = ((int)status & 4) == 4;
           bool EMG  = ((int)status & 8) == 8;
           bool ORG  = ((int)status & 16) == 16;
           bool SLP  = ((int)status & 64) == 64;
           bool SLN  = ((int)status & 128) == 128;
           bool INP  = ((int)status & 256) == 256;
           bool EZ   =  ((int)status & 512) == 512;
           bool RDY  = ((int)status & 1024) == 1024;
           bool DSTP = ((int)status & 2048) == 2048;


           //long lStandardIo1 = 0;

            if (ALM)
            {
                lStandardIo |= (0x01 << 0);
  
            }
            else if (ELP)
            {
                lStandardIo |= (0x01 << 1);
            }
            else if (ELN)
            {
                lStandardIo |= (0x01 << 2);
            }
            else if (EMG)
            {
                lStandardIo |= (0x01 << 4);

            }
            else if (ORG)
            {
                lStandardIo |= (0x01 << 3);
            }

            if (GetServoState(nAxisNo))
            {
                lStandardIo |= (0x01 << 7);
            }
            return lStandardIo;
        }

        public override bool GetServoState(int nAxisNo)
        {
            var ret = LTDMC.dmc_read_sevon_pin(_ConnecNo, (ushort)nAxisNo);
            return ret == 0;
        }

        public override bool Home(int nAxisNo, int nParam)
        {
            //LTDMC.smc_set_pulse_outmode(_ConnecNo, (ushort)nAxisNo, 0);//设置脉冲模式
            //LTDMC.smc_set_home_pin_logic(_ConnecNo, (ushort)nAxisNo, 0, 0);//设置原点低电平有效


            var ret = LTDMC.dmc_set_home_profile_unit(_ConnecNo, (ushort)nAxisNo, 
                m_HomePrm[nAxisNo].VelL * (m_MovePrm[nAxisNo].PlusePerRote / m_MovePrm[nAxisNo].AxisLeadRange),
                m_HomePrm[nAxisNo].VelH * (m_MovePrm[nAxisNo].PlusePerRote / m_MovePrm[nAxisNo].AxisLeadRange),
                m_HomePrm[nAxisNo].AccH,
                m_HomePrm[nAxisNo].DccH);//设置起始速度、运行速度、停止速度、加速时间、减速时间
            if (ret != 0)
            {
                return false;
            }


            ret = LTDMC.dmc_set_homemode(_ConnecNo, (ushort)nAxisNo, m_HomePrm[nAxisNo]._bHomeDir ? (ushort)1 : (ushort)0, 1, (ushort)m_HomePrm[nAxisNo]._nHomeMode, 0);//设置回零模式

            if(ret!=0)
            {
                return false;
            }
             ret = LTDMC.dmc_set_home_position_unit(_ConnecNo, (ushort)nAxisNo, 1,0);//设置偏移模式
            if (ret != 0)
            {
                return false;

            }
            ret = LTDMC.dmc_home_move(_ConnecNo, (ushort)nAxisNo);//启动回零
            if (ret != 0)
            {
                return false;
            }
            return true;
        }

        public override AxisState IsAxisNormalStop(int nAxisNo)
        {
            uint status = LTDMC.dmc_axis_io_status(_ConnecNo, (ushort)nAxisNo);
            if (((int)status & 1) == 1)
                return AxisState.DriveAlarm;
            if (((int)status & 2) == 2)
                return AxisState.LimtPStop;
            if (((int)status & 4) == 4)
                return AxisState.LimtNStop;
            if (!GetServoState(nAxisNo))
                return AxisState.ServoOff;
            var ret = IsInpos(nAxisNo);
            return ret ? AxisState.NormalStop : AxisState.Moving;
        }

        public override AxisState IsHomeNormalStop(int nAxisNo)
        {
            uint status = LTDMC.dmc_axis_io_status(_ConnecNo, (ushort)nAxisNo);
            if (((int)status & 1) == 1)
                return AxisState.DriveAlarm;
            if (((int)status & 2) == 2)
                return AxisState.LimtPStop;
            if (((int)status & 4) == 4)
                return AxisState.LimtNStop;
            if (!GetServoState(nAxisNo))
                return AxisState.ServoOff;
            return IsInpos(nAxisNo) ? AxisState.NormalStop : AxisState.Homeing;
        }

        public override bool IsInpos(int nAxisNo)
        {
            bool ret = LTDMC.dmc_check_done(_ConnecNo, (ushort)nAxisNo) == 1;
            if (ret )
            {
               
            }
            //return LTDMC.smc_check_done(_ConnecNo, (ushort)nAxisNo) == 0;


            return ret;
        }

        public override bool IsOpen()
        {
            return m_bOpen;
        }

        public override bool isOrgTrig(int nAxisNo)
        {
            throw new NotImplementedException();
        }

        public override bool JogMove(int nAxisNo, bool bPositive, int bStart, double nSpeed)
        {
            //LTDMC.smc_set_pulse_outmode(_ConnecNo, (ushort)nAxisNo, 0);//设置脉冲模式
            //LTDMC.smc_set_s_profile(_ConnecNo, (ushort)nAxisNo, 0, 0.01);//设置S段时间（0-0.05s)
            short ret = 0;
            switch (nSpeed)
            {
                case 0:
                    ret = LTDMC.dmc_set_profile_unit(_ConnecNo, (ushort)nAxisNo, 500, 
                        m_MovePrm[nAxisNo].VelH * (m_MovePrm[nAxisNo].PlusePerRote / m_MovePrm[nAxisNo].AxisLeadRange),
                        m_MovePrm[nAxisNo].AccH ,
                        m_MovePrm[nAxisNo].DccH , 100);//设置起始速度、运行速度、停止速度、加速时间、减速时间
                    break;

                case 1:
                    ret = LTDMC.dmc_set_profile_unit(_ConnecNo, (ushort)nAxisNo, 500,
                        m_MovePrm[nAxisNo].VelL * (m_MovePrm[nAxisNo].PlusePerRote / m_MovePrm[nAxisNo].AxisLeadRange),
                        m_MovePrm[nAxisNo].AccL ,
                        m_MovePrm[nAxisNo].DccL , 100);//设置起始速度、运行速度、停止速度、加速时间、减速时间
                    break;
            }
            //LTDMC.smc_set_dec_stop_time(_ConnecNo, (ushort)nAxisNo, m_MovePrm[nAxisNo].DccL);//设置减速停止时间
            ret = LTDMC.dmc_vmove(_ConnecNo, (ushort)nAxisNo, (ushort)(bPositive ? 1 : 0));//连续运动
            return true;
        }

        public override bool Open()
        {
            short num = LTDMC.dmc_board_init();
            int cardCount = 0;
            if (num <= 0 || num > 8)
            {
                num = GetCardList(ref cardCount, ref cardtypelist, ref cardidlist);
                if (cardCount == 0)
                {
                    num = -1;
                    return false;
                }
            }
            else
            {
                num = GetCardList(ref cardCount, ref cardtypelist, ref cardidlist);
            }
            ushort err = 0;
            int res = LTDMC.nmc_get_errcode(_ConnecNo, 2, ref err);//获取总线状态
            if (res == 0)
            {
                if (err != 0)//总线报错
                {
                    DateTime dt_start = DateTime.Now;
                    res = LTDMC.dmc_soft_reset(_ConnecNo);//复位总线错误
                    if (res != 0)
                    {
                        return false;
                    }
                    while (true)
                    {
                        if ((DateTime.Now - dt_start).TotalMilliseconds >= 20000.0)//超时退出循环
                        {
                            return false;
                        }
                        res = LTDMC.nmc_get_errcode(_ConnecNo, 2, ref err);
                        if (res == 0)
                        {
                            if (err == 0)//总线复位正常完成
                            {
                                break;
                            }
                        }
                        else
                        {
                            return false;
                        }
                    }
                }
            }


            string strConfigPath = "Motion_" + m_nCardIndex + ".ini";
            if(File.Exists(strConfigPath))
            {
                short s_Result = LTDMC.dmc_download_configfile(_ConnecNo, strConfigPath);
                s_Result = LTDMC.dmc_download_configfile_ex(_ConnecNo, strConfigPath);
                if (s_Result != 0)
                {
                    MessageBox.Show($"加载文件：{strConfigPath}失败");
                }
            }
            if (num == 0)
            {
                m_bOpen = true;
            }
            else
            {
                m_bOpen = false;
            }
            return num == 0;


        }
        public  uint[] cardtypelist = (uint[])null;
        public  ushort[] cardidlist = (ushort[])null;

        private short GetCardList(ref int num, ref uint[] cardtypelist, ref ushort[] cardidlist)
        {
            ushort CardNum = 0;
            uint[] CardTypeList = new uint[8];
            ushort[] CardIdList = new ushort[8];
            short cardInfList = LTDMC.dmc_get_CardInfList(ref CardNum, CardTypeList, CardIdList);
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendFormat("dmc_get_CardInfList({0},", (object)CardNum);
            stringBuilder.Append("[");
            for (int index = 0; index < (int)CardNum; ++index)
                stringBuilder.AppendFormat("{0},", (object)CardTypeList[index].ToString("X"));
            stringBuilder.Append("],");
            stringBuilder.Append("[");
            for (int index = 0; index < (int)CardNum; ++index)
                stringBuilder.AppendFormat("{0},", (object)CardIdList[index].ToString());
            stringBuilder.Append("]");
            stringBuilder.AppendFormat(")={0}", (object)cardInfList);

            if ((int)cardInfList != 0)
                return cardInfList;
            num = (int)CardNum;
            cardtypelist = new uint[num];
            cardidlist = new ushort[num];
            for (int index = 0; index < num; ++index)
            {
                cardtypelist[index] = (uint)CardTypeList[index] & 1048575;
                cardidlist[index] = CardIdList[index];
            }
            return cardInfList;
        }

        public override bool ReasetAxis(int nAxisNo)
        {
            LTDMC.nmc_clear_axis_errcode(_ConnecNo, (ushort)nAxisNo);
            return true;
        }

        public override bool RelativeMove(int nAxisNo, double nPos, double nSpeed)
        {
            
            short ret = 0;
            switch (nSpeed)
            {
                //最高速受运行比例速度影响
                case 0:
                    double d_Radio =GetMotorType(nAxisNo)== MotorType.SEVER? MotionMgr.GetInstace().d_Radio:1;
                    ret = LTDMC.dmc_set_profile_unit(_ConnecNo, (ushort)nAxisNo, 500, m_MovePrm[nAxisNo].VelH * (m_MovePrm[nAxisNo].PlusePerRote / m_MovePrm[nAxisNo].AxisLeadRange) * d_Radio, 
                        m_MovePrm[nAxisNo].AccH, m_MovePrm[nAxisNo].DccH , 0);//设置起始速度、运行速度、停止速度、加速时间、减速时间
                    break;
                case 1:
                    ret = LTDMC.dmc_set_profile_unit(_ConnecNo, (ushort)nAxisNo, 500, m_MovePrm[nAxisNo].VelL * (m_MovePrm[nAxisNo].PlusePerRote / m_MovePrm[nAxisNo].AxisLeadRange), 
                        m_MovePrm[nAxisNo].AccL , 
                        m_MovePrm[nAxisNo].DccL , 0);//设置起始速度、运行速度、停止速度、加速时间、减速时间
                    break;
                default:
                    ret = LTDMC.dmc_set_profile_unit(_ConnecNo, (ushort)nAxisNo, 500, nSpeed * (m_MovePrm[nAxisNo].PlusePerRote / m_MovePrm[nAxisNo].AxisLeadRange),
                                                     m_MovePrm[nAxisNo].AccL,
                                                     m_MovePrm[nAxisNo].DccL, 0);//设置起始速度、运行速度、停止速度、加速时间、减速时间
                    break;
            }
            if (ret != 0)
            {
                return false;
            }
            ret = LTDMC.dmc_set_s_profile(_ConnecNo, (ushort)nAxisNo, 0, 0.1);
            if (ret != 0)
            {
                return false;
            }
            ret =  LTDMC.dmc_pmove_unit(_ConnecNo, (ushort)nAxisNo, nPos, 0);//连续运动
            if (ret != 0)
            {
                return false;
            }
            return true;
        }

        public override bool ServoOff(short nAxisNo)
        {
            LTDMC.dmc_write_sevon_pin(_ConnecNo, (ushort)nAxisNo, (ushort)1);
            return true;
        }

        public override bool ServoOn(short nAxisNo)
        {


            short ret=  LTDMC.dmc_write_sevon_pin(_ConnecNo, (ushort)nAxisNo, (ushort)0);
            return true;
        }

        public override bool SetActutalPos(int nAxisNo, double pos)
        {
            pos = pos * GetAxisPulsesPerMM(nAxisNo);
            if (GetMotorType(nAxisNo) == MotorType.STEP)
                LTDMC.dmc_set_position_unit(_ConnecNo, (ushort)nAxisNo,  pos);
            else
                LTDMC.dmc_set_encoder_unit(_ConnecNo, (ushort)nAxisNo,  pos);
            return true;
        }

        public override bool SetCmdPos(int nAxisNo, double pos)
        {
            pos = pos * GetAxisPulsesPerMM(nAxisNo);
            LTDMC.dmc_set_position_unit(_ConnecNo, (ushort)nAxisNo, pos);//位置清零
            return true;
        }

        public override bool StartBufMove(object objGroup)
        {
            ushort CrdNo = (ushort)list.IndexOf(objGroup);

            var ret = LTDMC.dmc_conti_start_list(_ConnecNo, CrdNo);
            return true;
        }

        public override bool StopAxis(int nAxisNo)
        {
            var ret = LTDMC.dmc_stop(_ConnecNo, (ushort)nAxisNo, 0);
            return true;
        }

        public override bool StopEmg(int nAxisNo)
        {
            var ret = LTDMC.dmc_stop(_ConnecNo, (ushort)nAxisNo, 1);
            return true;
        }

        public override bool TranMMToPluse(int nAxisNo, ref double dSpeed, ref double acc, ref double dec)
        {
            double speed = dSpeed;
            double Acc = m_MovePrm[nAxisNo].AccH;
            double Dcc = m_MovePrm[nAxisNo].AccL;
            switch (dSpeed)
            {
                case (int)SpeedType.High:
                    Acc = m_MovePrm[nAxisNo].AccH;
                    Dcc = m_MovePrm[nAxisNo].DccH;
                    speed = m_MovePrm[nAxisNo].VelH;
                    break;
                case (int)SpeedType.Low:
                    Acc = m_MovePrm[nAxisNo].AccL;
                    Dcc = m_MovePrm[nAxisNo].DccL;
                    speed = m_MovePrm[nAxisNo].VelL;
                    break;
            }
            //新添转换
            dSpeed = speed = (1 * speed / m_MovePrm[nAxisNo].AxisLeadRange) * m_MovePrm[nAxisNo].PlusePerRote / 1;//- 1- 1
            return true;
        }

        public override bool TransMMToPluseForHomeParam(int nAxisNo, ref double dVelH, ref double dVelL, ref double dAccH, ref double dAccL, ref double dDecH, ref double dDecL)
        {
            return true;
        }
        public override bool ReadSDOData(int nAxis, short nSlave, ushort Index, byte nSubIndex = 0, uint nUnitNum = 16)
        {
            return true;
        }
        public override bool WriteSDOData(int nAxis, short nSlave, int val, ushort Index, byte nSubIndex = 0, uint nUnitNum = 16)
        {
            return true;
        }
        public override string GetAxisErrorString(int nAxisNo)
        {
            ushort errCode = 0;
            short error = LTDMC.nmc_get_axis_errcode(_ConnecNo, (ushort)nAxisNo, ref errCode);
            return errCode.ToString();
        }

    }
}